﻿/*
 * md5.h
 */
#ifndef __GDK_MD5_H__
#define __GDK_MD5_H__

#include <gdk/core/Types.h>
#include <gdk/core/String.h>
#include <gdk/core/Buffer.h>


namespace gdk
{


/* Unlike previous versions of this code, uint32 need not be exactly
   32 bits, merely 32 bits or more.  Choosing a data type which is 32
   bits instead of 64 is not important; speed is considerably more
   important.  ANSI guarantees that "unsigned long" will be big enough,
   and always using it seems to have few disadvantages.  */

struct MD5Context {
	uint32_t  buf[4];
	uint32_t  bits[2];
	uint8_t   in[64];
};

struct MD5Checksum {
	Buffer	data;
public:
	GDK_CORE_EXPORT String convertToString(void) const;
	GDK_CORE_EXPORT bool convertFromString(const String& text);

	__INLINE__ bool operator ==(const MD5Checksum &r) const { return data == r.data; }
	__INLINE__ bool operator !=(const MD5Checksum &r) const { return !(*this == r); }

public:
	template<typename TyIs> friend TyIs& operator >>(TyIs &is, MD5Checksum &md5) __THROW1;
	template<typename TyOs> friend TyOs& operator <<(TyOs &os, const MD5Checksum &md5) __THROW1;
};


GDK_CORE_EXPORT void MD5Init(MD5Context *context);
GDK_CORE_EXPORT void MD5Update(MD5Context *context, const void *buf, size_t len);
GDK_CORE_EXPORT void MD5Transform(uint32_t buf[4], const uint8_t in[64]);
GDK_CORE_EXPORT void MD5Final(uint8_t digest[16], MD5Context *context);
GDK_CORE_EXPORT void MD5Final(MD5Checksum *checksum, MD5Context *context);


template<typename TyIs>
TyIs& operator >>(TyIs &is, MD5Checksum &md5) __THROW1
{
	switch (md5.data.getBufferSize()) {
	case 0: case 16: break;
	default: __THROW__(__TEXT__("TyIs& operator >>(TyIs &is, MD5Checksum &md5)"));
	}
	return is >> md5.data;
}
template<typename TyOs>
TyOs& operator <<(TyOs &os, const MD5Checksum &md5) __THROW1
{
	os << md5.data;
	switch (md5.data.getBufferSize()) {
	case 0: case 16: break;
	default: __THROW__(__TEXT__("TyOs& operator <<(TyOs &os, const MD5Checksum &md5)"));
	}
	return os;
}

//------------------------------------------------------------------------
__INLINE__ void convertPropertyToClass(const JsonValue &json, MD5Checksum &md5) __THROW1
{
	if (!json.isString() || !md5.convertFromString(json.asString()))
	{
		__THROW__(__TEXT__("void convertPropertyToClass(const String &, MD5Checksum &)"));
	}
}
__INLINE__ void convertPropertyToJson(const MD5Checksum &md5, JsonValue &json) __THROW1
{
	json = md5.convertToString();
}



}//namespace gdk


#endif /* __GDK_MD5_H__ */


